package com.dd.common.base

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding
import java.lang.reflect.ParameterizedType

abstract class BaseActivity<B : ViewBinding, V : BaseViewModelAbs<*>> : AppCompatActivity() {
    protected var binding: B? = null
    protected var model: V? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setLayout()
        initUI()
    }

    override fun onDestroy() {
        super.onDestroy()
        binding = null
    }

    protected open fun setLayout() {
        binding = getViewBinding()
        binding?.let {
            setContentView(it.root)
        }
        model = getViewModel()
        model?.let {
            it.setContext(this)
            initObserver()
        }
    }

    protected fun setLayout(inflater: LayoutInflater, container: ViewGroup) {
        val viewBindingClass: Class<B>
        val viewModelClass: Class<V>
        try {
            val type = javaClass.genericSuperclass ?: return
            val types = (type as ParameterizedType).actualTypeArguments
            if (types.size < 2) {
                Log.e("BaseActivity", "泛型不完整")
                return
            }

            viewBindingClass = types[0] as Class<B>
            viewModelClass = types[1] as Class<V>
            val method = viewBindingClass.getMethod(
                "inflate", *arrayOf(
                    LayoutInflater::class.java,
                    ViewGroup::class.java,
                    Boolean::class.javaPrimitiveType
                )
            )
            binding = method.invoke(
                viewBindingClass,
                *arrayOf(inflater, container, java.lang.Boolean.FALSE)
            ) as B

            model = ViewModelProvider(this)[viewModelClass]
            model?.let { viewModel ->
                viewModel.setContext(this)
                viewModel.getIsShowProgress().observe(this) { isShow ->
                    if (isShow) {
                        showProgress()
                    } else {
                        hideProgress()
                    }
                }
                viewModel.getNoticeMessage().observe(this) { noticeMessage ->
                    showNotice(
                        noticeMessage.type,
                        noticeMessage.message
                    )
                }
            }
            initObserver()
        } catch (e: Exception) {
            e.printStackTrace()
            return
        }
    }

    protected open fun initObserver() {
        model?.let {
            it.getIsShowProgress().observe(this) { isShow ->
                if (isShow) {
                    showProgress()
                } else {
                    hideProgress()
                }
            }

            it.getNoticeMessage().observe(this) { noticeMessage ->
                showNotice(
                    noticeMessage.type,
                    noticeMessage.message
                )
            }
        }
    }

    fun showNotice(type: Int, notice: String) {
    }

    fun showProgress() {
    }

    fun hideProgress() {}

    protected abstract fun getViewBinding(): B
    protected abstract fun getViewModel(): V
    protected abstract fun initUI()
}